package com.woniuxy.yoga.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniuxy.yoga.business.dao.mapper.BusinessAccountMapper;
import com.woniuxy.yoga.business.dao.mapper.BusinessStoreMapper;
import com.woniuxy.yoga.business.dao.model.BusinessAccount;
import com.woniuxy.yoga.business.dao.model.BusinessPayment;
import com.woniuxy.yoga.business.dao.mapper.BusinessPaymentMapper;
import com.woniuxy.yoga.business.dao.model.BusinessStore;
import com.woniuxy.yoga.business.model.dto.businessaccount.BusinessAccountDTO;
import com.woniuxy.yoga.business.model.dto.businesspayment.BusinessPaymentDTO;
import com.woniuxy.yoga.business.model.exception.BusinessException;
import com.woniuxy.yoga.business.model.exception.BusinessExceptionCode;
import com.woniuxy.yoga.business.model.form.businesspayment.PaymentLogForm;
import com.woniuxy.yoga.business.model.param.businesspayment.BusinessPagePayParam;
import com.woniuxy.yoga.business.model.param.businesspayment.SelectPagePaymentParam;
import com.woniuxy.yoga.business.service.BusinessPaymentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.yoga.commons.alipay.data.AlipayParam;
import com.woniuxy.yoga.commons.alipay.util.AlipayUtil;
import com.woniuxy.yoga.commons.core.model.PageInfo;
import com.woniuxy.yoga.commons.core.statedata.BusinessState;
import com.woniuxy.yoga.commons.core.util.DateUtil;
import com.woniuxy.yoga.commons.redis.util.rediskeyutil.BusinessRedisKeyUtil;
import com.xxl.job.core.handler.annotation.XxlJob;
import io.seata.spring.annotation.GlobalTransactional;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.temporal.ChronoField;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

/**
 * <p>
 * 商家入驻缴费表 服务实现类
 * </p>
 *
 * @author 韦用文, 刘存益, 郎腾霄
 * @since 2023年12月02日
 */
@Service
public class BusinessPaymentServiceImpl extends ServiceImpl<BusinessPaymentMapper, BusinessPayment> implements BusinessPaymentService {

    @Autowired
    private BusinessPaymentMapper businessPaymentMapper;
    @Autowired
    private AlipayUtil alipayUtil;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private BusinessStoreMapper businessStoreMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private BusinessAccountMapper businessAccountMapper;

    /**
     *响应给商家支付页面
     * @param param
     * @return
     */
    @Override
    public String businessPagePay(BusinessPagePayParam param) throws Exception {
        //检查是否存在未缴纳的入驻费
        LambdaQueryWrapper<BusinessPayment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BusinessPayment::getPaymentId, param.getPaymentId()).eq(BusinessPayment::getAccountId,param.getAccountId());
        BusinessPayment businessPayment = businessPaymentMapper.selectOne(queryWrapper);
        if (businessPayment==null) {
            throw new BusinessException(BusinessExceptionCode.BUSINESS_EXCEPTION_CODE_PAYMENT_NOTEXIST);
        }
        if (businessPayment.getPaymentState()!= BusinessState.ENTER_MONEY_STATE_NO_PAY) {
            throw new BusinessException(BusinessExceptionCode.BUSINESS_EXCEPTION_CODE_PAYMENT_STATEERROR);
        }
        //发起支付
        AlipayParam alipayParam = new AlipayParam();
        alipayParam.setOutTradeNo(param.getPaymentId());
        //同步回调
        alipayParam.setReturnUrl(param.getReturnUrl());
        alipayParam.setTotalAmount(businessPayment.getPaymentMoney());
        alipayParam.setSubject("芦苇瑜伽");
        //异步回调
        alipayParam.setNotifyUrl(AlipayUtil.NAT_APP_URL_LIU+"/business/businessPayment/paySuccess");
        alipayParam.setBody("入驻芦苇瑜伽平台缴费");
        return alipayUtil.payPage(alipayParam);
    }

    /**
     * 商家入驻缴费异步回调
     * @param params
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void paySuccess(Map<String, String> params) throws Exception {
        //验签
        if (alipayUtil.checkSignature(params)) {
            //取出缴费ID和缴费状态
            String paymentId = params.get(AlipayUtil.ORDER_NUM);
            String tradeStatus = params.get(AlipayUtil.PAY_STATUS);
            if (AlipayUtil.STATUS_SUCCESS.equals(tradeStatus)) {
                //对缴费加锁
                RLock lock = redissonClient.getFairLock(BusinessRedisKeyUtil.getLockPaymentIdKey(paymentId));
                try {
                    if (lock.tryLock(10, TimeUnit.SECONDS)) {
                        //查出入驻缴费信息
                        LambdaQueryWrapper<BusinessPayment> queryWrapper = new LambdaQueryWrapper<>();
                        queryWrapper.eq(BusinessPayment::getPaymentId,paymentId);
                        BusinessPayment businessPayment = businessPaymentMapper.selectOne(queryWrapper);
                        if (businessPayment!=null&&businessPayment.getPaymentState()== BusinessState.ENTER_MONEY_STATE_NO_PAY) {
                            //查询门店信息
                            LambdaQueryWrapper<BusinessStore> wrapper = new LambdaQueryWrapper<>();
                            wrapper.eq(BusinessStore::getAccountId,businessPayment.getAccountId());
                            BusinessStore businessStore = businessStoreMapper.selectOne(wrapper);
                            //取出缴费时间记录
                            String date = params.get(AlipayUtil.PAY_TIME);
                            businessPayment.setPaymentTime(date);
                            LocalDateTime startTime = DateUtil.StringToLocalDateTime(date);
                            LocalDateTime endTime = startTime.plusDays(30L);
                            businessPayment.setEndTime(DateUtil.localDateTimeToString(endTime, "yyyy-MM-dd HH:mm:ss"));
                            //修改缴费状态
                            businessPayment.setPaymentState(BusinessState.ENTER_MONEY_STATE_PAYED);
                            businessPaymentMapper.updateById(businessPayment);
                            businessStore.setEnterMoneyState(BusinessState.ENTER_MONEY_STATE_PAYED);
                            businessStore.setEnterPayTime(date);
                            businessStoreMapper.updateById(businessStore);
                            //消息队列生成缴费日志
                            PaymentLogForm paymentLogForm = BeanUtil.toBean(businessPayment, PaymentLogForm.class);
                            paymentLogForm.setPayMoney(businessPayment.getPaymentMoney());
                            paymentLogForm.setPayTime(businessPayment.getPaymentTime());
                            paymentLogForm.setStoreId(businessStore.getStoreId());
                            //在消息队列中异步执行
                            rabbitTemplate.convertAndSend("create-businessPaymentLog",paymentLogForm);
                            //设置定时任务，入驻时间到期后修改门店状态并生成新的缴费信息
                            String xxlLoginAPI="http://192.168.90.27:9999/xxl-job-admin/login";
                            String xxlAddJobAPI="http://192.168.90.27:9999/xxl-job-admin/jobinfo/add";
                            HashMap<String, Object> loginParam = new HashMap<>();
                            loginParam.put("userName","admin");
                            loginParam.put("password","123456");
                            HttpResponse httpResponse = HttpRequest.post(xxlLoginAPI).form(loginParam).execute();
                            if (httpResponse.getStatus()==200) {
                                HashMap<String, Object> addTaskParam = new HashMap<>();
                                addTaskParam.put("jobGroup",4);//执行器
                                LocalDateTime executeTime = endTime;//设置过期时间
                                int year = executeTime.get(ChronoField.YEAR);
                                int month = executeTime.get(ChronoField.MONTH_OF_YEAR);
                                int day = executeTime.get(ChronoField.DAY_OF_MONTH);
                                int hour=executeTime.get(ChronoField.HOUR_OF_DAY);
                                int minute=executeTime.get(ChronoField.MINUTE_OF_HOUR);
                                int second=executeTime.get(ChronoField.SECOND_OF_MINUTE);
                                StringBuilder cron = new StringBuilder();
                                cron.append(second);
                                cron.append(" "+minute);
                                cron.append(" "+hour);
                                cron.append(" "+day);
                                cron.append(" "+month);
                                cron.append(" ?");
                                cron.append(" "+year);
                                addTaskParam.put("scheduleConf", cron.toString());
                                addTaskParam.put("jobDesc", "入驻时间到期");//任务名称
                                addTaskParam.put("author", "pengyuyan");//作者
                                addTaskParam.put("executorHandler", "paymentExpire");//到期处理
                                addTaskParam.put("executorParam",paymentId);//支付记录编号
                                addTaskParam.put("scheduleType", "CRON");//调度类型
                                addTaskParam.put("executorRouteStrategy", "FIRST");//路由策略
                                addTaskParam.put("executorBlockStrategy", "SERIAL_EXECUTION");//阻塞处理策略
                                addTaskParam.put("glueType", "BEAN");//运行模式
                                addTaskParam.put("misfireStrategy","DO_NOTHING");//调度过期策略
                                addTaskParam.put("executorTimeout", "0");//任务超时时间
                                addTaskParam.put("executorFailRetryCount","0");//失败重试次数
                                addTaskParam.put("triggerStatus", 1);//定时任务触发状态
                                HttpResponse response = HttpRequest.post(xxlAddJobAPI).form(addTaskParam).execute();
                                System.out.println(response.body());
                            }
                        }
                    }
                } finally {
                    lock.unlock();
                }

            }
        }
    }

    /**
     * 分页查询缴费信息
     * @param param
     * @return
     */
    @Override
    public PageInfo selectPagePayment(SelectPagePaymentParam param) {
        //商家是否存在
        BusinessAccount businessAccount = businessAccountMapper.selectById(param.getAccountId());
        if (businessAccount==null) {
            throw new BusinessException(BusinessExceptionCode.BUSINESS_EXCEPTION_CODE_ACCOUNT_NOTEXITS);
        }
        //商家账号状态是否正常
        if (businessAccount.getAccountState()!= BusinessState.BUSINESS_ACCOUNT_STATE_NORMAL) {
            throw new BusinessException(BusinessExceptionCode.BUSINESS_EXCEPTION_CODE_ACCOUNT_STATEERROR);
        }
        LambdaQueryWrapper<BusinessPayment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BusinessPayment::getAccountId,param.getAccountId());
        //开始分页
        Page<BusinessPayment> page = new Page<>(param.getCurrent()==null?1:param.getCurrent(),param.getSize()==null?5:param.getSize());
        businessPaymentMapper.selectPage(page,queryWrapper);
        PageInfo pageInfo = BeanUtil.toBean(page, PageInfo.class);
        pageInfo.setPages(page.getPages());
        pageInfo.setRecords(BeanUtil.copyToList(page.getRecords(), BusinessPaymentDTO.class));
        return pageInfo;
    }
}
